package com.ecoolex.hotel.saas.core.manager;

import com.ecoolex.framework.common.enums.ResultCode;
import com.ecoolex.framework.common.pojo.Page;
import com.ecoolex.framework.common.pojo.Pagination;
import com.ecoolex.framework.common.pojo.Sorting;
import com.ecoolex.framework.common.pojo.Sortings;
import com.ecoolex.framework.common.util.BeanUtil;
import com.ecoolex.framework.common.util.BizAssert;
import com.ecoolex.framework.common.util.Check;
import com.ecoolex.hotel.saas.core.dao.StoreAdDAO;
import com.ecoolex.hotel.saas.entity.StoreAd;
import com.ecoolex.hotel.saas.entity.StoreAd.Column;
import com.ecoolex.hotel.saas.entity.StoreAdExample;
import com.ecoolex.hotel.saas.entity.StoreAdPosition;
import com.ecoolex.hotel.saas.enums.StoreAdStatus;
import com.ecoolex.hotel.saas.pojo.QueryStoreAdDTO;
import com.google.common.collect.Lists;

import java.time.Instant;
import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class StoreAdManager {
	
    @Autowired
    private StoreAdDAO dao;
    
    @Autowired
    private StoreAdPositionManager positionManager;

    private void verify(StoreAd record) {
        BizAssert.isTrue(Check.notNullOrTrimEmpty(record.getName()), ResultCode.VERIFY.build(101), "名称为空");
        BizAssert.isTrue(Check.notNullOrTrimEmpty(record.getImage()), ResultCode.VERIFY.build(102), "图片为空");
        BizAssert.isTrue(Check.notNullOrTrimEmpty(record.getAction()), ResultCode.VERIFY.build(103), "动作类型为空");
        BizAssert.isTrue(Check.notNull(record.getWeight()), ResultCode.VERIFY.build(104), "权重为空");
        BizAssert.isTrue(Check.notNull(record.getEnablingTime()), ResultCode.VERIFY.build(105), "启用时间为空");
        BizAssert.isTrue(Check.notNull(record.getExpiryTime()), ResultCode.VERIFY.build(106), "失效时间为空");
        BizAssert.isTrue(record.getEnablingTime().before(record.getExpiryTime()),
            ResultCode.VERIFY.build(107),
            "启用时间在失效时间之后");
    }

    @Transactional
    public StoreAd add(StoreAd record, List<StoreAdPosition> positionList, String createUser) {
        verify(record);
        record.setStatus(StoreAdStatus.OFFLINE.real());
        record.setDeleted(StoreAd.NOT_DELETED);
        record.setCreateUser(createUser);
        record.setCreateTime(Date.from(Instant.now()));
        record.setUpdateUser(createUser);
        record.setUpdateTime(Date.from(Instant.now()));

        dao.insert(record);

        positionManager.updatePositionByAd(record, positionList, createUser);
        return record;
    }

    @Transactional
    public StoreAd update(StoreAd record, List<StoreAdPosition> positionList, String updateUser) {
        BizAssert.isTrue(Check.notNull(record.getAdId()), ResultCode.BIZ.build(111), "广告Id为空");
        StoreAd old = dao.selectByPrimaryKeyWithLogicalDelete(record.getAdId(), StoreAd.NOT_DELETED);
        BizAssert.isTrue(Check.notNull(old), ResultCode.BIZ.build(111), "广告为空");
        BizAssert.isTrue(StoreAdStatus.RELEASE.notEqual(old.getStatus()), ResultCode.BIZ.build(111), "发布状态无法修改");
        // 验证
        verify(record);
        // 复制修改的值
        BeanUtil.copy(record,
            old,
            Lists.newArrayList(Column.adId,
                Column.status,
                Column.deleted,
                Column.createUser,
                Column.createTime,
                Column.updateUser,
                Column.updateTime).stream().map(Column::getJavaProperty).toArray(String[]::new));

        record.setUpdateUser(updateUser);
        record.setUpdateTime(Date.from(Instant.now()));

        // 修改部分字段
        dao.updateByPrimaryKeySelective(old,
            Column.excludes(Column.adId, Column.status, Column.storeId, Column.deleted, Column.createUser, Column.createTime));
        // 修改位置配置
        positionManager.updatePositionByAd(record, positionList, updateUser);

        return old;
    }

    @Transactional
    public void delete(int adId, String updateUser) {
        StoreAd old = dao.selectByPrimaryKeyWithLogicalDelete(adId, StoreAd.NOT_DELETED);
        BizAssert.isTrue(Check.notNull(old), ResultCode.BIZ.build(111), "广告为空");
        BizAssert.isTrue(StoreAdStatus.RELEASE.notEqual(old.getStatus()), ResultCode.BIZ.build(112), "发布状态无法删除");

        old.setDeleted(StoreAd.IS_DELETED);
        old.setUpdateUser(updateUser);
        old.setUpdateTime(Date.from(Instant.now()));

        dao.updateByPrimaryKeySelective(old, Column.deleted, Column.updateUser, Column.updateTime);

        positionManager.deleteByAdId(old.getAdId());
    }

    @Transactional
    public void release(int adId, String updateUser) {
        StoreAd record = dao.selectByPrimaryKeyWithLogicalDelete(adId, StoreAd.NOT_DELETED);
        BizAssert.isTrue(Check.notNull(record), ResultCode.BIZ.build(111), "广告为空");
        BizAssert.isTrue(StoreAdStatus.RELEASE.notEqual(record.getStatus()), ResultCode.BIZ.build(112), "发布状态无法发布");
        BizAssert.isTrue(record.getExpiryTime().after(Date.from(Instant.now())),
            ResultCode.BIZ.build(113),
            "无法发布已失效广告");

        StoreAdExample example = new StoreAdExample();
        example.createCriteria().andAdIdEqualTo(adId).andStatusEqualTo(record.getStatus()).andDeletedEqualTo(
            record.getDeleted());

        record.setStatus(StoreAdStatus.RELEASE.real());
        record.setUpdateUser(updateUser);
        record.setUpdateTime(Date.from(Instant.now()));

        int row = dao.updateByExampleSelective(record, example, Column.status, Column.updateUser, Column.updateTime);

        BizAssert.isTrue(row == 1, ResultCode.BIZ.build(120), "发布失败");
    }

    @Transactional
    public void offline(int adId, String updateUser) {
        StoreAd record = dao.selectByPrimaryKeyWithLogicalDelete(adId, StoreAd.NOT_DELETED);
        BizAssert.isTrue(Check.notNull(record), ResultCode.BIZ.build(111), "广告为空");
        BizAssert.isTrue(StoreAdStatus.RELEASE.equal(record.getStatus()), ResultCode.BIZ.build(114), "非发布状态无法下线");

        StoreAdExample example = new StoreAdExample();
        example.createCriteria().andAdIdEqualTo(adId).andStatusEqualTo(record.getStatus()).andDeletedEqualTo(
            record.getDeleted());

        record.setStatus(StoreAdStatus.OFFLINE.real());
        record.setUpdateUser(updateUser);
        record.setUpdateTime(Date.from(Instant.now()));

        int row = dao.updateByExampleSelective(record, example, Column.status, Column.updateUser, Column.updateTime);

        BizAssert.isTrue(row == 1, ResultCode.BIZ.build(120), "下线失败");
    }

    /**
     * 检查过期的数据并修改状态
     * 
     * @param updateUser
     * @return
     */
    public int checkExpiredAndUpdateStatus(String updateUser) {
        StoreAd record = new StoreAd();
        record.setStatus(StoreAdStatus.EXPIRED.real());
        record.setUpdateUser(updateUser);
        record.setUpdateTime(Date.from(Instant.now()));

        StoreAdExample example = new StoreAdExample();
        example.createCriteria().andStatusEqualTo(StoreAdStatus.RELEASE.real()).andExpiryTimeLessThan(
            Date.from(Instant.now())).andDeletedEqualTo(StoreAd.NOT_DELETED);

        return dao.updateByExampleSelective(record, example, Column.status, Column.updateUser, Column.updateTime);
    }

    public Pagination<StoreAd> query(QueryStoreAdDTO query, Sorting[] sorts, Page page) {
        return Pagination.create(page, dao.count(query), () -> dao.query(query, Sortings.builder(sorts).toSql(), page));
    }

    public List<StoreAd> queryEffective(Integer storeId, String position, String[] positionValue, int size) {
        return dao.queryEffective(storeId, position, positionValue, size);
    }

    public StoreAd getByAdId(int adId) {
        return dao.selectByPrimaryKeyWithLogicalDelete(adId, StoreAd.NOT_DELETED);
    }
}